package com.app.common.core;

import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

import com.app.common.utils.BeanUtilsX;
import com.app.common.utils.Utils;
import com.app.common.vo.DebeziumMessage;

/**
 * 
 * @author 北京八维博大科技 薛建新
 * @date 2022年12月23日 11:24:01
 * @Copyright 北京八维博大科技
 */
public abstract class CrudMessageHandler<T, ID> extends BaseMessageHandler<T, ID> {

//	private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CrudMessageHandler.class);

	public final String KEY_ID = "id";// 看情况可以修改为大写ID

	/**
	 * 获取dao
	 * 
	 * @author xuejx
	 * @return
	 */
	public abstract IDAO<T, ID> getDAO();

	/**
	 * 获取实体class
	 * 
	 * @author xuejx
	 * @return
	 */
	public abstract Class<T> getEntityClass();

	public final ID buildId(DebeziumMessage msg, Function<Map<String, Object>, ID> idMapper) {
		ID id = null;
		if (null != msg.getAfter()) {
			id = idMapper.apply(msg.getAfter());
		}
		if (null == id && null != msg.getBefore()) {
			id = idMapper.apply(msg.getBefore());
		}
		return id;
	}

	@SuppressWarnings("unchecked")
	public ID buildId(DebeziumMessage msg) {
		return buildId(msg, (map) -> {
			return (ID) map.get(KEY_ID);
		});
	}

	protected final T getEmptyEntity() {
		try {
			return (T) getEntityClass().getDeclaredConstructor().newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 按业务主键查询
	 * 
	 * @author xuejx
	 * @param id
	 * @return
	 */
	public Optional<T> queryByBizID(ID id) {
		return getDAO().findById(id);
	}

	/**
	 * 按业务主键删除
	 * 
	 * @author xuejx
	 * @param id
	 * @return
	 */
	public void deleteByBizID(ID id) {
		getDAO().deleteById(id);
	}

	/**
	 * 保存
	 * 
	 * @author xuejx
	 * @return
	 */
	public void save(T obj) {
		getDAO().save(obj);
	}

	@Override
	protected T handleDelete(DebeziumMessage msg) {
		var dataKey = buildId(msg);
		var optEn = queryByBizID(dataKey);
		if (optEn.isPresent()) {
			deleteByBizID(dataKey);
			return optEn.get();
		}
		return null;
	}

	@Override
	protected T handleUpdate(DebeziumMessage msg) {
		var dataKey = buildId(msg);
		var optEn = queryByBizID(dataKey);
		var en = optEn.orElse(getEmptyEntity());
		if (optEn.isPresent()) {// 更新时如何实现部分更新?先删后插？部分更新？
			// 把map中的值合并到en
			BeanUtilsX.mapToBean(en, Utils.underlineToCamel(msg.getAfter()));
			// 有则更新无则插入
			save(en);
		} else {// 数据不存在，用 after 覆盖before,然后插入 before
			msg.getBefore().putAll(msg.getAfter());
			BeanUtilsX.mapToBean(en, Utils.underlineToCamel(msg.getBefore()));
			save(en);
		}
		return en;
	}

	@Override
	protected T handleCreate(DebeziumMessage msg) {
		var en = getEmptyEntity();
		// 把map中的值合并到en
		BeanUtilsX.mapToBean(en, Utils.underlineToCamel(msg.getAfter()));
		// 有则更新无则插入,为什么都是更新 需要_new 来标识数据是新增
		save(en);
		return en;
	}

}
